<!--
 * @Author: jiu yin
 * @Date: 2024-04-11 14:04:23
 * @LastEditTime: 2024-04-30 15:40:09
 * @LastEditors: jiu yin zhen jing
 * @FilePath: \web-smart-tour\src\pagesA\ar_navigation\components\ai_chat.vue
 * jiu
-->
<template>
	<view class="content" :style="{
		transform: switch_value_computed ? 'scale(1)' : 'scale(0)',
		opacity: switch_value_computed ? '1' : '0',
	}">
		<!-- ar_识别 -->
		<image v-if="fileDeploy.ai.ar_scan" src="https://resources.ym2meta.com/web-smart-tour/ar_recognition.png"
			class="w-108rpx h-108rpx absolute top-0 right-48rpx z-20" @click="ar_recognition"></image>
		<!-- 人 -->

		<image :src="ai_chat_img_off" class="w-300rpx h-618rpx absolute top-108rpx right-0rpx z--1" mode="widthFix"
			v-show="!answer_person"></image>
		<image :src="ai_chat_img_on" class="w-300rpx h-618rpx absolute top-108rpx right-0rpx z--1" mode="widthFix"
			v-show="answer_person"></image>

		<scroll-view scroll-y="true" id="ai_scroll" class="h-90% box-border pl-20rpx pr-80rpx pointer-events-auto"
			:scroll-into-view="scrollInto">
			<!-- 聊天信息 -->
			<view v-for="(item, index) in list" :key="index">
				<!-- 问 -->
				<view class="flex items-center mb-24rpx">
					<image :src="ossurl(item.question_avatar, 'user_face')" mode="aspectFill"
						class="w-56rpx h-56rpx border-rd-50% border-solid border-2rpx border-#fff mr-20rpx"></image>
					<view class="bg border-rd-24rpx flex-1 p-14rpx text-#FFF font-size-28rpx break-all"
						v-if="item.mode == 1">
						{{ item.question }}
					</view>
					<image v-if="item.mode == 2" :src="ossurl(item.question)" mode="aspectFill" @click="previewImage(item)"
						class="ar_recognition_img w-200rpx h-200rpx border-#fff border-rd-24rpx border-solid border-2rpx">
					</image>
				</view>
				<!-- 答 -->
				<view class="flex items-center mb-24rpx" v-show="item.answer">
					<image :src="answer_avatar" mode="aspectFill"
						class="w-56rpx h-56rpx border-rd-50% border-solid border-2rpx border-#fff mr-20rpx"></image>
					<view class="bg border-rd-24rpx flex-1 p-14rpx">
						<view class="answerAds" v-if="item.ads" v-for="(val, key) in item.ads" :key="key">
							<image :src="ossurl(val)" mode="widthFix"></image>
						</view>	
						<view class="text-#FFF font-size-28rpx break-all">{{ item.answer }}</view>
					</view>
				</view>
			</view>

			<!-- 加载 -->
			<view class="flex items-center mb-24rpx" v-show="ai_loading.question_loading">
				<image :src="ossurl(userInfo.avatar, 'user_face')" mode="aspectFill"
					class="w-56rpx h-56rpx border-rd-50% border-solid border-2rpx border-#fff mr-20rpx"></image>
				<view class="bg border-rd-24rpx flex-1 p-14rpx text-#FFF font-size-28rpx">加载中 ...</view>
			</view>

			<view class="flex items-center mb-24rpx" v-show="ai_loading.answer_loading">
				<image :src="answer_avatar" mode="aspectFill"
					class="w-56rpx h-56rpx border-rd-50% border-solid border-2rpx border-#fff mr-20rpx"></image>
				<view class="bg border-rd-24rpx flex-1 p-14rpx text-#FFF font-size-28rpx">加载中 ...</view>
			</view>

			<view id="scrollBottom" class="text-center"
				:style="{ color: map_nav_type_computed === 'map_nav' ? '#000' : '#fff' }">
				<!-- --------- AI 聊天记录 --------- -->
			</view>
		</scroll-view>
	</view>
</template>

<script>
import { mapGetters } from 'vuex';
import { ossurl, ossUploadFile, getImgInfo, compressImg } from '@/utils/index';
import { history, service, uploadSignature } from '@/api/home';
import { NODE_ENV } from '@/utils/request';

export default {
	props: ['spotAuth'],
	data() {
		return {
			scrollInto: '',
			NODE_ENV: NODE_ENV,
			list: [],
			answer_avatar: '',
			scrollTop: 0,
			scenic_detail: JSON.parse(uni.getStorageSync('scenic_detail')) || {},
			audioContext: null,
			ai_chat_img_off: '',
			ai_chat_img_on: '',
			err: [],
		};
	},
	onLoad(options) { },
	computed: {
		...mapGetters(['is_logined', 'userInfo', 'fileDeploy']),
		switch_value_computed() {
			return this.$store.getters.switch_value;
		},
		ai_loading() {
			this.$nextTick(() => {
				this.autoScroll();
			});
			return this.$store.getters.ai_loading;
		},
		map_nav_type_computed() {
			return this.$store.getters.map_nav_type;
		},
		answer_person() {
			return this.$store.getters.answer_person;
		},
	},

	mounted() {
		this.answer_avatar = ossurl(this.fileDeploy?.ai?.avatar);
		this.ai_chat_img_off = ossurl(this.fileDeploy?.ai?.portrait_static);
		this.ai_chat_img_on = ossurl(this.fileDeploy?.ai?.portrait_trends);

		this.history_fn();
		this.audioContext = uni.createInnerAudioContext();
	},
	unmounted() {
		this.audioContext = null;
	},
	updated() {
		// this.autoScroll();
	},
	methods: {
		ossurl,
		previewImage(item) {
			uni.previewImage({
				urls: [ossurl(item.question)],
			});
		},
		async history_fn() {
			let { data } = await history({ spot_id: this.scenic_detail.spot_id });
			this.list = data.map((item) => ({
				...item,
				mode: item.mode ? item.mode : 1,
				question_avatar: this.userInfo.avatar,
				answer_avatar: this.answer_avatar,
			}));
			this.autoScroll();
		},
		message(obj) {
			if (obj.type == 'question') {
				this.list.push({ question: obj.data, mode: obj.mode, question_avatar: this.userInfo.avatar });
			} else if (obj.type == 'answer') {
				this.list.at(-1).ads = obj.ads;
				this.list.at(-1).answer = obj.data;
				this.list.at(-1).answer_avatar = this.answer_avatar;
				const audioData = obj.audio;
				if (audioData) {
					this.playAudio(audioData);
				}
			}
		},
		dataURLtoFile(dataurl, filename, mime) {
			var bstr = atob(dataurl),
				n = bstr.length,
				u8arr = new Uint8Array(n);
			while (n--) {
				u8arr[n] = bstr.charCodeAt(n);
			}
			return new File([u8arr], filename, { type: mime });
		},
		downLoadFile(dataUrl, file_path) {
			return new Promise((resolve, reject) => {
				uni.getFileSystemManager().writeFile({
					filePath: file_path,
					data: dataUrl,
					encoding: 'base64',
					success: (res) => {
						resolve(res);
					},
					fail: (res) => {
						reject(res);
					},
				});
			});
		},
		async playAudio(audioData) {
			//当前时间戳
			const rnd = Date.now();
			const filename = `ai_chat_${this.userInfo.id}_${rnd}.mp3`;
			const file_path = wx.env.USER_DATA_PATH + '/audio_' + filename;
			// console.log('音频文件存储位置', file_path, audioData);
			await this.downLoadFile(audioData, file_path);
			const innerAudioContext = this.audioContext;
			innerAudioContext.src = file_path;
			innerAudioContext.onPlay(() => {
				console.log('开始播放');
				this.$store.commit('map/set_answer_person', true);
			});
			innerAudioContext.onError((res) => {
				this.$store.commit('map/set_answer_person', false);
				console.log(res.errorCode);
				console.log(res.errorMsg);
			});
			innerAudioContext.onStop(() => {
				this.$store.commit('map/set_answer_person', false);
			});
			innerAudioContext.onPause(() => {
				this.$store.commit('map/set_answer_person', false);
			});
			innerAudioContext.onEnded(() => {
				console.log('结束播放');
				this.$store.commit('map/set_answer_person', false);
				try {
					uni.getFileSystemManager().unlinkSync(file_path);
				} catch (e) { }
			});
			innerAudioContext.play(); //播放音频
		},
		//第一次滚动条至最底部
		autoScroll() {
			let timeout = null;
			this.scrollInto = '';
			clearTimeout(timeout);
			timeout = setTimeout(() => {
				this.scrollInto = 'scrollBottom';
			}, 300);
		},
		ar_recognition() {
			//没权限
			if (!this.spotAuth.purchase_status && (!this.spotAuth.experience || this.spotAuth.experience_end_time_stamp == 0)) {
				return this.$emit('no_spotAuth');
			}

			let _this = this;
			uni.chooseImage({
				count: 1,
				sizeType: ['original', 'compressed'],
				sourceType: ['album', 'camera'],
				camera: 'back',
				async success(res) {
					this.err = [];
					//获取图片名字等信息 避免压缩后获取不到
					let filePath = res.tempFiles[0].path;
					console.log('filePath', filePath, res.tempFiles);
					let _date = new Date();
					let ext_name = filePath.substr(filePath.lastIndexOf('.'));
					let address = _date.getFullYear() + '' + (_date.getMonth() + 1) + '' + _date.getDate();
					let fileName = address + _date.getTime() + ext_name;
					const img_info = await getImgInfo(filePath);
					let { width, height } = img_info;
					let maxWidth = 800;
					if (width > maxWidth) {
						let scale = Math.ceil(width / maxWidth);
						height = Math.ceil(height / scale);
						width = Math.ceil(maxWidth);
					}
					let compress_path = '';
					compress_path = await compressImg(filePath, { compressedWidth: width }).catch((res) => {
						console.log('上传压缩失败', err);
					});
					compress_path = compress_path ? compress_path : filePath;

					_this.upload_img(compress_path, fileName);
					console.log(compress_path, fileName, '拍摄成功');
				},
			});
		},
		errToast() {
			uni.showModal({
				title: '提示',
				content: JSON.stringify(this.err),
				success: function (res) {
					if (res.confirm) {
						console.log('用户点击确定');
					} else if (res.cancel) {
						console.log('用户点击取消');
					}
				},
			});
		},
		async upload_img(filePath, fileName) {
			try {
				uni.showLoading({
					title: '图片上传中',
				});
				const { file_url = '' } = await ossUploadFile(filePath, fileName)
					.finally(() => {
						uni.hideLoading();
					})
					.catch((res) => {
						console.log('ossUploadFile==', res);
						uni.$u.toast('ar识别图片失败!!');
					});
				if (!file_url) {
					uni.$u.toast('ar识别图片失败!!!!!');
					return;
				}
				console.log('上传图片成功imgUrl==', file_url);
				this.message({ type: 'question', mode: 2, data: file_url });
				this.$store.commit('map/set_ai_loading', { answer_loading: true });

				let { data, code, msg = '' } = await service({ input_text: file_url, spot_id: this.scenic_detail.spot_id, mode: 2 });
				if (code != 200) {
					uni.$u.toast(msg);
					return;
				}
				this.$store.commit('map/set_ai_loading', { answer_loading: false });
				var mes = { type: 'answer', data: data.text, ads: data.ads };
				if(data.is_file == true)
				{
					mes.audio = data.audio;
				}
				this.message(mes);
			} catch (err) {
				console.log('ar识别图片失败', err);
				uni.$u.toast('ar识别图片失败~~');
				this.message({ type: 'answer', data: 'ar识别图片失败' });
			}
		},
	},
};
</script>

<style lang="scss" scoped>
.content {
	height: calc(100vh - 780rpx);
	overflow: hidden;
	box-sizing: border-box;
	//margin-top: 36rpx;
	position: relative;
	z-index: 22;
	transition: 0.3s ease-out;
	transform: scale(0);

	.bg {
		background-color: rgba(2, 43, 32, 0.5);
	}

	.ar_recognition_img {
		position: relative;

		&::before {
			content: '';
			position: absolute;
			top: 0;
			left: 0;
			width: 94rpx;
			height: 36rpx;
			background: url('/static/images/ar_recognition_tag.png') no-repeat;
			background-size: 100% 100%;
		}
	}
}
.answerAds{ width: 100%; height: auto; margin:10rpx auto;}
.answerAds image{ width: 300rpx; height: auto;}
</style>
